#include "buffer.h"

size_t Buffer::ReadAble() const
{
    return writepos_ - readpos_;
}

size_t Buffer::WriteAble() const
{
    return buffer_.size() - writepos_;
}

size_t Buffer::PrependableBytes() const
{
    return readpos_;
}

const char *Buffer::Peek() const
{
    return BeginPtr_() + readpos_;
}

void Buffer::EnsureWriteAble(int len)
{
    if (WriteAble() < len)
        MakePlace_(len);
    assert(WriteAble() >= len);
}

void Buffer::HasWritten(int len)
{
    assert(WriteAble() < buffer_.size());
    writepos_ += len;
}

void Buffer::HasReaded(int len)
{
    assert(ReadAble() >= len);
    readpos_ += len;
}

void Buffer::ReadUtil(const char *end)
{
    assert(end > Peek());
    HasReaded(end - Peek());
}

void Buffer::ClearBuffer()
{
    bzero(&buffer_[0], buffer_.size());
    readpos_ = 0;
    writepos_ = 0;
}
std::string Buffer::ClearBufferToStr()
{
    std::string str(readpos_, ReadAble());
    ClearBuffer();
    return str;
}

void Buffer::MakePlace_(int len)
{
    if (WriteAble() + PrependableBytes() < len)
    {
        buffer_.resize(readpos_ + len + 1);
    }
    else
    {
        size_t readable = ReadAble();
        std::copy(BeginPtr_() + readpos_, BeginPtr_() + writepos_, BeginPtr_());
        readpos_ = 0;
        writepos_ = readpos_ + readable;
        assert(readable == ReadAble());
    }
}

const char *Buffer::BeginPtr_() const
{
    return &buffer_[0];
};
char *Buffer::BeginPtr_()
{
    return &buffer_[0];
};

const char *Buffer::BeginWriteConst() const
{
    return BeginPtr_() + writepos_;
};
char *Buffer::BeginWrite()
{
    return BeginPtr_() + writepos_;
}

//-------------------------------
// 保证容量可以
//-------------------------------
void Buffer::Append(const char *str, size_t len)
{
    assert(str);
    EnsureWriteAble(len);
    std::copy(str, str + len, BeginPtr_()+writepos_);
    HasWritten(len);
}

void Buffer::Append(const std::string &str)
{
    Append(str.c_str(), str.size());
}

void Buffer::Append(const void *data, size_t len)
{
    assert(data);
    Append(static_cast<const char *>(data), len);
}
void Buffer::Append(const Buffer &buffer)
{
    Append(buffer.Peek(), ReadAble());
}

ssize_t Buffer::ReadFd(int fd, int *Errno)
{
    char buffer[65535];
    struct iovec iov[2];
    size_t writeable = WriteAble();
    iov[0].iov_base = BeginPtr_() + writepos_;
    iov[0].iov_len = WriteAble();
    iov[1].iov_base = buffer;
    iov[1].iov_len = sizeof(buffer) - 1;
    const ssize_t len = readv(fd, iov, 2);
    if (len < 0)
    {
        *Errno = errno;
    }
    else if (static_cast<size_t>(len) <= ReadAble())
        HasReaded(len);
    else
    {
        writepos_ = buffer_.size();
        Append(buffer, len - writeable);
    }
    return len;
}

ssize_t Buffer::WriteFd(int fd, int *Errno)
{
    ssize_t readable = ReadAble();
    ssize_t len = write(fd, Peek(), readable);
    if (len < 0)
        *Errno = errno;
    else
        HasReaded(len);
    return len;
}

Buffer::Buffer(size_t initbuffersize):readpos_(0),writepos_(0),buffer_(initbuffersize)
{}

Buffer::~Buffer() = default;